//+------------------------------------------------------------------+
//|                                                         6666.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// 输入参数
input ulong      InpMagicNumber = 123456;     // EA魔术编号

input int        InpTradeDirection = 1;       // 交易方向(0=只做空,1=只做多)
input int        InpGridStep = 300;           // 网格间距(点)
input int        InpFirstStopLoss = 300;      // 首单止损点数
input double     InpMultiplier = 2;           // 止损乘数参数
input int        InpSlippage = 3;             // 允许滑点

// 加仓手数配置（共17个层级）
input double     InpLotSize1 = 0.01;          // 加仓手数1
input double     InpLotSize2 = 0.01;          // 加仓手数2
input double     InpLotSize3 = 0.03;          // 加仓手数3
input double     InpLotSize4 = 0.05;          // 加仓手数4
input double     InpLotSize5 = 0.10;          // 加仓手数5
input double     InpLotSize6 = 0.18;          // 加仓手数6
input double     InpLotSize7 = 0.34;          // 加仓手数7
input double     InpLotSize8 = 0.61;          // 加仓手数8
input double     InpLotSize9 = 1.10;          // 加仓手数9
input double     InpLotSize10 = 1.98;         // 加仓手数10
input double     InpLotSize11 = 3.57;         // 加仓手数11
input double     InpLotSize12 = 0.64;         // 加仓手数12
input double     InpLotSize13 = 1.10;         // 加仓手数13
input double     InpLotSize14 = 3.30;         // 加仓手数14
input double     InpLotSize15 = 4.30;         // 加仓手数15
input double     InpLotSize16 = 5.00;         // 加仓手数16
input double     InpLotSize17 = 6.00;         // 加仓手数17

// 全局变量
double lotSizes[17]; // 存储各层手数的数组

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // 初始化手数数组
   lotSizes[0]  = InpLotSize1;
   lotSizes[1]  = InpLotSize2;
   lotSizes[2]  = InpLotSize3;
   lotSizes[3]  = InpLotSize4;
   lotSizes[4]  = InpLotSize5;
   lotSizes[5]  = InpLotSize6;
   lotSizes[6]  = InpLotSize7;
   lotSizes[7]  = InpLotSize8;
   lotSizes[8]  = InpLotSize9;
   lotSizes[9]  = InpLotSize10;
   lotSizes[10] = InpLotSize11;
   lotSizes[11] = InpLotSize12;
   lotSizes[12] = InpLotSize13;
   lotSizes[13] = InpLotSize14;
   lotSizes[14] = InpLotSize15;
   lotSizes[15] = InpLotSize16;
   lotSizes[16] = InpLotSize17;
   
   Print("EA初始化完成，最大加仓层级：17");
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print("EA卸载完成，原因代码：", reason);
}
//+------------------------------------------------------------------+
//| 平仓所有持仓                                                     |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   string symbol = Symbol();
   for(int i = PositionsTotal()-1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      
      if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber || 
         PositionGetString(POSITION_SYMBOL) != symbol)
         continue;
      
      MqlTradeRequest request;
      ZeroMemory(request);
      request.action = TRADE_ACTION_DEAL;
      request.position = ticket;
      request.symbol = symbol;
      request.volume = PositionGetDouble(POSITION_VOLUME);
      request.deviation = InpSlippage;
      request.magic = InpMagicNumber;
      
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         request.type = ORDER_TYPE_SELL;
      else
         request.type = ORDER_TYPE_BUY;
      
      MqlTradeResult result;
      bool sent = OrderSend(request, result);
      
      if(sent) Print("平仓成功，手数：", request.volume);
      else Print("平仓失败，错误代码：", result.retcode);
   }
}

//+------------------------------------------------------------------+
//| 止损检查函数                                                     |
//+------------------------------------------------------------------+
void CheckStopLoss()
{
   string symbol = Symbol();
   int totalPositions = 0;
   double totalLots = 0;
   double totalProfit = 0;
   double maxPointsLoss = 0;
   
   for(int i = PositionsTotal()-1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      
      if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber || 
         PositionGetString(POSITION_SYMBOL) != symbol)
         continue;
         
      totalPositions++;
      double volume = PositionGetDouble(POSITION_VOLUME);
      totalLots += volume;
      totalProfit += PositionGetDouble(POSITION_PROFIT);
      
      // 计算首单点数亏损
      if(totalPositions == 1)
      {
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
         ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         
         if(posType == POSITION_TYPE_BUY)
            maxPointsLoss = (openPrice - currentPrice)/_Point;
         else
            maxPointsLoss = (currentPrice - openPrice)/_Point;
      }
   }
   
   if(totalPositions == 0) return;
   
   // 首单止损逻辑
   if(totalPositions == 1)
   {
      if(maxPointsLoss >= InpFirstStopLoss)
      {
         Print("触发首单止损(",maxPointsLoss,"点)");
         CloseAllPositions();
      }
   }
   // 多单止损逻辑
   else if(totalPositions > 1)
   {
      double stopLossAmount = totalLots * 100 * InpMultiplier;
      if(totalProfit <= -stopLossAmount)
      {
         Print("触发多单止损(亏损:",totalProfit," 阈值:",-stopLossAmount,")");
         CloseAllPositions();
      }
   }
}
//+------------------------------------------------------------------+
//| 解析注释中的层级数字                                             |
//+------------------------------------------------------------------+
int ParseCommentLevel(const string comment)
{
   if(StringFind(comment, "Level") == 0)
   {
      string levelStr = StringSubstr(comment, 5);
      return (int)StringToInteger(levelStr);
   }
   return 0; // 非本EA订单返回0
}

//+------------------------------------------------------------------+
//| 开仓函数                                                         |
//+------------------------------------------------------------------+
bool OpenPosition(int level, string symbol, double lot)
{
   // 验证交易方向
   if(InpTradeDirection != 0 && InpTradeDirection != 1)
   {
      Print("错误：无效交易方向参数");
      return false;
   }
   
   // 确定订单类型和价格
   ENUM_ORDER_TYPE orderType;
   double price = 0;
   if(InpTradeDirection == 1)
   {
      orderType = ORDER_TYPE_BUY;
      price = SymbolInfoDouble(symbol, SYMBOL_ASK);
   }
   else
   {
      orderType = ORDER_TYPE_SELL;
      price = SymbolInfoDouble(symbol, SYMBOL_BID);
   }
   
   // 构建交易请求
   MqlTradeRequest request = {};
   request.action = TRADE_ACTION_DEAL;
   request.symbol = symbol;
   request.volume = lot;
   request.type = orderType;
   request.price = price;
   request.deviation = InpSlippage;
   request.magic = InpMagicNumber;
   request.comment = "Level" + IntegerToString(level);
   
   // 发送交易请求
   MqlTradeResult result;
   bool success = OrderSend(request, result);
   
   // 处理结果
   if(success)
   {
      Print("成功开仓#", level, " 类型:", EnumToString(orderType), " 手数:", lot, " 价格:", price);
      return true;
   }
   else
   {
      Print("开仓失败#", level, " 错误码:", result.retcode);
      return false;
   }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   CheckStopLoss(); // 新增止损检查
   
   string symbol = Symbol();
   int currentLevel = GetCurrentPositionLevel(symbol);
   
   // 无持仓时开首单
   if(currentLevel == 0)
   {
      TryOpenFirstPosition(symbol);
      return;
   }
   
   // 已达最大层级不再加仓
   if(currentLevel >= 17)
   {
      Print("已达最大层级17，停止加仓");
      return;
   }
   
   // 检查加仓条件
   CheckAddPositionCondition(symbol, currentLevel);
}

//+------------------------------------------------------------------+
//| 获取当前持仓层级                                                 |
//+------------------------------------------------------------------+
int GetCurrentPositionLevel(const string symbol)
{
   int maxLevel = 0;
   
   for(int i = PositionsTotal()-1; i >= 0; i--)
   {
      if(!PositionGetTicket(i)) continue;
      
      // 检查MagicNumber和交易品种
      if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber || 
         PositionGetString(POSITION_SYMBOL) != symbol) continue;
      
      // 解析注释中的层级
      int level = ParseCommentLevel(PositionGetString(POSITION_COMMENT));
      if(level > maxLevel) maxLevel = level;
   }
   
   Print("当前持仓层级：", maxLevel);
   return maxLevel;
}

//+------------------------------------------------------------------+
//| 尝试开首单                                                       |
//+------------------------------------------------------------------+
void TryOpenFirstPosition(const string symbol)
{
   Print("无持仓，尝试开首单");
   if(!OpenPosition(1, symbol, lotSizes[0]))
   {
      Print("首单开仓失败！");
   }
}

//+------------------------------------------------------------------+
//| 检查加仓条件                                                     |
//+------------------------------------------------------------------+
void CheckAddPositionCondition(const string symbol, const int currentLevel)
{
   double lastPrice = GetLastPositionPrice(symbol);
   double currentPrice = GetCurrentPrice(symbol);
   double targetPrice = CalculateTargetPrice(lastPrice, currentLevel);
   
   bool conditionMet = IsAddPositionConditionMet(currentPrice, targetPrice);
   
   if(conditionMet)
   {
      Print("满足加仓条件，当前价格：", currentPrice, " 目标价格：", targetPrice);
      OpenPosition(currentLevel+1, symbol, lotSizes[currentLevel]);
   }
   else
   {
      Print("不满足加仓条件，当前价格：", currentPrice, " 需要价格：", targetPrice);
   }
}

//+------------------------------------------------------------------+
//| 获取最后持仓价格                                                 |
//+------------------------------------------------------------------+
double GetLastPositionPrice(const string symbol)
{
   double lastPrice = 0;
   
   for(int i = PositionsTotal()-1; i >= 0; i--)
   {
      if(!PositionGetTicket(i)) continue;
      
      if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber && 
         PositionGetString(POSITION_SYMBOL) == symbol)
      {
         lastPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         break;
      }
   }
   
   return lastPrice;
}

//+------------------------------------------------------------------+
//| 获取当前价格                                                     |
//+------------------------------------------------------------------+
double GetCurrentPrice(const string symbol)
{
   return (InpTradeDirection == 1) ? 
          SymbolInfoDouble(symbol, SYMBOL_ASK) : 
          SymbolInfoDouble(symbol, SYMBOL_BID);
}

//+------------------------------------------------------------------+
//| 计算目标价格                                                     |
//+------------------------------------------------------------------+
double CalculateTargetPrice(const double lastPrice, const int currentLevel)
{
   return lastPrice + 
          (InpTradeDirection == 1 ? 1 : -1) * 
          InpGridStep * _Point;
}

//+------------------------------------------------------------------+
//| 判断是否满足加仓条件                                             |
//+------------------------------------------------------------------+
bool IsAddPositionConditionMet(const double currentPrice, const double targetPrice)
{
   return (InpTradeDirection == 1) ? 
          (currentPrice >= targetPrice) : 
          (currentPrice <= targetPrice);
}
//+------------------------------------------------------------------+